/*
 * Copyright 2006-2007 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package sant

import java.io.File

import com.google.code.sant.Ant._
import com.google.code.sant._
import com.google.code.sant.cli.OptionBuilder

import org.apache.tools.ant.{Project => AntProject}
import org.apache.commons.cli.{Option => CliOption, Options => CliOptions, CommandLine, CommandLineParser, GnuParser, HelpFormatter, ParseException}

/**
 * @author Sergey Nebolsin
 */
object SantRunner {
  val options = new CliOptions()
  options.addOption(new CliOption( "h", "help", false, "print this message" ))
  options.addOption(new CliOption( "p", "projecthelp", false, "print project help information" ))
  options.addOption(new CliOption( "version", "print the version information and exit" ))
  options.addOption(new CliOption( "q", "quiet", false, "be extra quiet" ))
  options.addOption(new CliOption( "v", "verbose", false, "be extra verbose" ))
  options.addOption(new CliOption( "d", "debug", false, "print debugging information" ))
  options.addOption(new OptionBuilder("buildfile","use given buildfile").withArgName("file").hasArg().create)
  options.addOption(new OptionBuilder("file","use given buildfile").withArgName("file").hasArg().create)
  options.addOption(new OptionBuilder("f","use given buildfile").withArgName("file").hasArg().create)
    
  var buildfile:String = "build.scala"
  var logLevel:Int = AntProject.MSG_INFO
    
  def proceedCommandLine(line:CommandLine) {
    if( line.hasOption( "help" ) ) {
      val formatter:HelpFormatter = new HelpFormatter()
      formatter.printHelp( "sant", options )
      return
    }
    
    if( line.hasOption( "debug" ) ) {
      logLevel = AntProject.MSG_DEBUG
    } else if( line.hasOption( "verbose" ) ){
      logLevel = AntProject.MSG_VERBOSE
    } else if( line.hasOption( "quiet" ) ) {
      logLevel = AntProject.MSG_WARN
    }
    
    if( line.hasOption( "buildfile" ) ) {
      buildfile = line.getOptionValue( "buildfile" )
    } else if( line.hasOption( "file" ) ) {
      buildfile = line.getOptionValue( "file" )
    } else if( line.hasOption( "f" ) ) {
      buildfile = line.getOptionValue( "f" )
    }
    
    projectVar.withValue(new SantProject) {
      try {
        project.initWithLogger(logLevel)
        project.load(new File(buildfile))
      
        if( line.hasOption( "projecthelp" ) ) {
          printDescription(project)
          printTargets(project, true)
          return
        }
      
        val buildStartTime = System.currentTimeMillis()
        project.go(line.getArgs().toList)
        project.info("\nBUILD SUCCESSFUL")
        project.info("Time: " + (System.currentTimeMillis() - buildStartTime) + "ms.")
      } catch {
        case e: SantException => {
          project.error( "BUILD FAILED: " + e.getMessage())
        }
      } finally {
        SantScriptLoader.cleanup
      }
    }
  }
  
  def main(args:Array[String]) {
    val parser:CommandLineParser = new GnuParser();
    try {
      val line:CommandLine = parser.parse( options, args );
      proceedCommandLine(line)
    } catch {
      case pe:ParseException => println( "Parsing failed.  Reason: " + pe.getMessage() );
    }
  }
  
  private def printDescription(project:SantProject) {
    if( project.description != null ) {
      project.warn(project.description)
    }
  }

  implicit def target2ordered(target: SantTarget): Ordered[SantTarget] = new Ordered[SantTarget] {
    def compare(other: SantTarget): Int = target.name.compare(other.name)
  }
  
  private def printTargets(project:SantProject, printSubTargets:Boolean) {
    val mainTargets = project.targets.map(_._2).filter(_.description != "")
    val otherTargets = project.targets.map(_._2).filter(_.description == "")
    
    val sep = System.getProperty("line.separator")
    var maxLength = 0
    mainTargets.foreach( target => if( target.name.length > maxLength ) maxLength = target.name.length )
    var spaces = "    "
    while( spaces.length <= maxLength ) spaces += spaces
    var message = new StringBuilder()
    message.append(sep).append("Main targets:").append(sep).append(sep)
    var sortedList = scala.util.Sorting.stableSort(mainTargets.toList)
    sortedList.foreach( target =>
      message.append(target.name).append(spaces.substring(0,spaces.length - target.name.length)).append(target.description).append(sep)
    )
    project.warn(message.toString())

    sortedList = scala.util.Sorting.stableSort(otherTargets.toList)
    if( printSubTargets ) {
      project.info(sep)
      val msg = sortedList.foldLeft("Other targets: ")( (msg,target) => msg + target.name + ", " )
      project.warn(msg.substring(0,msg.length - 2))
    }
  }
   
}
